﻿using System.ComponentModel;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;

namespace DatabaseGroup.SSIS.SourceAdapters.View
{
    /// <summary>
    /// Column information class for use primarily with the properties grid
    /// </summary>
    [DefaultPropertyAttribute("Name")]
    public class ColumnProperty
    {
        /// <summary>
        /// Event to indicate that the column is being updated
        /// </summary>
        public event CancelPropertyUpdateEventHandler Updating;

        private string _name;
        private int _precision;
        private int _scale;
        private DataType _datatype;
        private int _length;
        private int _codepage;
        private string _truncationHandling;
        private string _errorHandling;

        /// <summary>
        /// Initializes a new instance of the ColumnProperty class using the provided 
        /// initial column properties
        /// </summary>
        /// <param name="name">The column name</param>
        /// <param name="precision">The column precision</param>
        /// <param name="scale">The column scale</param>
        /// <param name="datatype">The column datatype</param>
        /// <param name="length">The column length</param>
        /// <param name="codepage">The column codepage</param>
        public ColumnProperty(string name, int precision, int scale, DataType datatype, int length, int codepage)
        {
            _name = name;
            _precision = precision;
            _scale = scale;
            _datatype = datatype;
            _length = length;
            _codepage = codepage;

            this.IsForOutput = true;
        }

        /// <summary>
        /// Gets or sets if the column is meant for the component standard output
        /// </summary>
        [Browsable(false)]
        public bool IsForOutput { get; set; }

        /// <summary>
        /// Gets or sets the truncation handling for the column
        /// </summary>
        [CategoryAttribute("Error Handling")]
        public string TruncationHandling
        {
            get
            {
                return _truncationHandling;
            }
            set
            { 
                string originalValue = _truncationHandling;
                _truncationHandling = value;

                if (CancelUpdate("TruncationHandling", originalValue, _truncationHandling))
                    _truncationHandling = originalValue;
            }
        }

        /// <summary>
        /// Gets or sets the error handling for the column
        /// </summary>
        [CategoryAttribute("Error Handling")]
        public string ErrorHandling
        {
            get
            {
                return _errorHandling;
            }
            set
            {
                string originalValue = _errorHandling;
                _errorHandling = value;

                if (CancelUpdate("ErrorHandling", originalValue, _errorHandling))
                    _errorHandling = originalValue;
            }
        }

        /// <summary>
        /// Gets or sets the column name
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("Name of the column")]
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                string originalValue = _name;
                _name = value;

                if (CancelUpdate("Name", originalValue, _name))
                    _name = originalValue;
            }
        }

        /// <summary>
        /// Gets the width of the input column (always 0 in this component)
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("The width of this column in the source file, given in single characters. Composite characters may need two or more single character spaces.")]
        public int InputColumnWidth
        {
            get
            {
                return 0;
            }
        }

        /// <summary>
        /// Gets or sets the column data precision (only set for numeric datatypes)
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("For numeric types")]
        public int DataPrecision
        {
            get
            {
                return _precision;
            }
            set
            {
                int originalValue = _precision;
                _precision = value;

                if (CancelUpdate("DataPrecision", originalValue, _precision))
                    _precision = originalValue;
            }
        }

        /// <summary>
        /// Gets or sets the column datascale (only set for numeric/decimal datatypes)
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("")]
        public int DataScale
        {
            get
            {
                return _scale;
            }
            set
            {
                int originalValue = _scale;
                _scale = value;

                if (CancelUpdate("DataScale", originalValue, _scale))
                    _precision = originalValue;
            }
        }

        /// <summary>
        /// Gets or sets the column datatype
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("Column datatype")]
        public DataType DataType
        {
            get
            {
                return _datatype;
            }
            set
            {
                DataType originalValue = _datatype;
                _datatype = value;

                if (CancelUpdate("DataType", originalValue, _datatype))
                    _datatype = originalValue;
            }
        }

        /// <summary>
        /// Gets or sets the column width/length (only set for string types)
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("Output column width")]
        public int OutputColumnWidth
        {
            get
            {
                return _length;
            }
            set
            {
                int originalValue = _length;
                _length = value;

                if (CancelUpdate("OutputColumnWidth", originalValue, _length))
                    _length = originalValue;
            }
        }

        /// <summary>
        /// Gets or sets the column codepage
        /// </summary>
        [CategoryAttribute("Misc"), DescriptionAttribute("The codepage for the column")]
        public int CodePage
        {
            get
            {
                return _codepage;
            }
            set
            {
                int originalValue = _codepage;
                _codepage = value;

                if (CancelUpdate("CodePage", originalValue, _codepage))
                    _codepage = originalValue;
            }
        }

        /// <summary>
        /// Sets core column properties in a single operation without
        /// triggering the Updating event
        /// </summary>
        /// <param name="datatype">The column datatype to set</param>
        /// <param name="length">The OutputColumnWidth to set</param>
        /// <param name="scale">The column DataScale to set</param>
        /// <param name="precision">The column DataPrecision to set</param>
        /// <param name="codepage">The column codepage to set</param>
        public void SetCoreColumnProperties(DataType datatype, int length, int scale, int precision, int codepage)
        {
            _datatype = datatype;
            _length = length;
            _scale = scale;
            _precision = precision;
            _codepage = codepage;
        }

        /// <summary>
        /// Checks to see if any Updating event listeners wish to 
        /// cancel the update event
        /// </summary>
        /// <param name="propertyName">The name of the property being updated</param>
        /// <param name="oldValue">The value the property is being changed from</param>
        /// <param name="newValue">The value the property is being changed to</param>
        /// <returns>True if the event should be cancelled</returns>
        private bool CancelUpdate(string propertyName, object oldValue, object newValue)
        {
            CancelPropertyUpdateEventArgs eventArgs = new CancelPropertyUpdateEventArgs(propertyName);
            eventArgs.OldValue = oldValue;
            eventArgs.NewValue = newValue;

            if (Updating != null)
                Updating(this, eventArgs);

            return eventArgs.Cancel;
        }
    }
}
